﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Contact.Contracts.Models.Worktime;
using EFDataModel;

namespace Contact.DAL.Models.Worktime
{
    /// <summary>
    /// Funktionen zum Verwalten von Daten für unserer Arbeitszeitverwaltungseinstellungen.
    /// </summary>
    public class WorktimeSettingsRepository : IWorktimeSettings
    {
        #region Interface Members
        /// <summary>
        /// Der Aktuelle ModelContainer
        /// </summary>
        public EFModelContainer CurrentModel { get; set; }

        /// <summary>
        /// Ermitteln der Worktimesettings für einen User
        /// </summary>
        /// <param name="userId">UserId für die die Settings herausgesucht werden sollen.</param>
        /// <returns>Ein einzelnes Worktimesetting oder Null wenn nichts gefunden wurde.</returns>
        public EFWorktimeSetting LoadWorktimeSetting(long userId)
        {
            //Das passende Setting für die übergebene UserId zurückgeben
            var setting = (from set in CurrentModel.EFBaseMenge.OfType<EFAuthentication>()
                          where set.ID == userId
                          select set.EFWorktimeSetting).FirstOrDefault();

            return setting;
        }

        /// <summary>
        /// Speichern der Einstellungen
        /// </summary>
        /// <param name="setting">Settings welches gespeichert werden soll.</param>
        /// <returns>TRUE->Speichern erfolgreich | FALSE->Speichern NICHT erfolgreich</returns>
        public bool SaveWorktimeSetting(EFWorktimeSetting setting)
        {
            try
            {
                //Da die Settings bereits geladen wurden, muss hier nur noch gespeichert werden.
                CurrentModel.SaveChanges();
            }
            catch (Exception exception)
            {
                EFDebugging.Debugging.WriteLog("SaveWorktimeSetting Exception", exception);
                return false;
            }

            return true;
        }   
        
        /// <summary>
        /// Anlegen und Speichern der Einstellungen
        /// </summary>
        /// <param name="setting">Settings welches gespeichert werden soll.</param>
        /// <param name="user">Der User für den das Setting gesetzt werden soll</param>
        /// <returns>TRUE->Speichern erfolgreich | FALSE->Speichern NICHT erfolgreich</returns>
        public bool AddWorktimeSetting(EFWorktimeSetting setting, EFAuthentication user)
        {
            //Wenn es sich um einen neuen Eintrag handelt, wird direkt noch der Eintrag für die Ferientage angelegt.
            if (setting.HolidayDays == null)
            {
                setting.HolidayDays = new Collection<HolidayDays>();
                setting.HolidayDays.Add(new HolidayDays { Days = 25, Year = setting.EmploymentStartDate.Year });
            }

            //Die übergebenen Settings beim übergebenen User setzten.
            user.EFWorktimeSetting = setting;

            try
            {
                //Speichern des Models
                CurrentModel.SaveChanges();
            }
            catch (Exception exception)
            {
                EFDebugging.Debugging.WriteLog("SaveWorktimeSetting Exception", exception);
                return false;
            }

            return true;
        }

        /// <summary>
        /// Laden der Liste mit den Projekten die dem übergebenen User zugeordnet sind.
        /// </summary>
        /// <param name="userId">UserId zu der alle Projekte herausgesucht werden sollen</param>
        public List<EFWorktimeProject> LoadProjects(long userId)
        {
            var user = (EFAuthentication) CurrentModel.EFBaseMenge.Find(userId);
            if (user != null)
            {
                return user.EFWorktimeSetting.EFWorktimeProject.OrderBy(p => p.Sortorder).ToList();
            }

            return new List<EFWorktimeProject>();
        }

        /// <summary>
        /// Laden der aktiven Projekte
        /// </summary>
        /// <param name="userId">Die UserId für die die aktiven Projekte geladen werden sollen.</param>
        public IQueryable<EFWorktimeProject> LoadActiveProjects(long userId)
        {
            var project = from worktimeProject in CurrentModel.EFWorktimeProjectSet
                          where
                              worktimeProject.EFWorktimeSetting.EFAuthentication.ID == userId &&
                              worktimeProject.ShowEntry
                          select worktimeProject;
            return project;
        }

        /// <summary>
        /// Löschen des übergebenen Projekteintrags
        /// </summary>
        /// <param name="projectId">Der Projekteintrag der entfernt werden soll.</param>
        public bool DeleteProject(long projectId)
        {
            try
            {
                //Versuchen das Projekt zu laden
                var project = CurrentModel.EFWorktimeProjectSet.Find(projectId);
                CurrentModel.EFWorktimeProjectSet.Remove(project);
                CurrentModel.SaveChanges();
                return true;
            }
            catch (Exception exception)
            {
                EFDebugging.Debugging.WriteLog("DeleteProject Exception", exception);
            }

            return false;
        }

        /// <summary>
        /// Laden des passenden Projektes anhand der übergebenen ProjektId
        /// </summary>
        /// <param name="projectId">Die ProjektId zu der die Daten geladen werden sollen</param>
        public EFWorktimeProject LoadProject(long projectId)
        {
            return CurrentModel.EFWorktimeProjectSet.Find(projectId);
        }

        /// <summary>
        /// Abrufen aller Urlaubszeiteinträge für die übergebene UserId
        /// </summary>
        /// <param name="userId">Der User für den die Urlaubszeiten abgerufen werden sollen.</param>
        public List<HolidayDays> LoadHolidays(long userId)
        {
            var user = (EFAuthentication) CurrentModel.EFBaseMenge.Find(userId);
            if (user != null)
            {
                return user.EFWorktimeSetting.HolidayDays.OrderBy(p=>p.Year).ToList();
            }

            return new List<HolidayDays>();
        }

        /// <summary>
        /// Abrufen des passenden Urlaubseintrags
        /// </summary>
        /// <param name="holidayId">den passenden Urlaubseintrag abrufen</param>
        public HolidayDays LoadHoliday(long holidayId)
        {
            return CurrentModel.HolidayDaysSatz.Find(holidayId);
        }

        /// <summary>
        /// Laden des Urlaubszeiteintrags für den User und das angegebene Jahr.
        /// </summary>
        /// <param name="userId">Die UserId für die die Urlaubseinträge gesucht werden sollen </param>
        /// <param name="year">Das Jahr nach dem gesucht werden soll</param>
        public HolidayDays LoadHolidayDays(long userId, int year)
        {
            var user = (EFAuthentication)CurrentModel.EFBaseMenge.Find(userId);
            if (user != null)
            {
                return user.EFWorktimeSetting.HolidayDays.FirstOrDefault(p => p.Year == year);
            }

            return null;
        }

        /// <summary>
        /// Speichern/Hinzufügen des übergebenen Holidayeintrags in der DB.
        /// </summary>
        /// <param name="holiday">Der Holidayeintrag, der in der DB hinzugefügt werden soll oder gespeichert werden soll.</param>
        /// <param name="userId">die zugehörige UserId zum Holidayeintrag.</param>
        /// <returns>TRUE->Speichern erfolgreich | FALSE->Fehler beim Speichern</returns>
        public bool SaveHoliday(HolidayDays holiday, long userId)
        {
            try
            {
                //Wenn die Id=0, dann wurde der Eintrag noch nicht der DB hinzugefügt.
                if (holiday.ID == 0)
                {
                    //Suchen des User, damit wir den Eintrag seiner Urlaubsliste hinzufügen können.
                    var user = (EFAuthentication) CurrentModel.EFBaseMenge.Find(userId);
                    if (user != null)
                    {
                        user.EFWorktimeSetting.HolidayDays.Add(holiday);
                    }
                    else
                    {
                        return false;
                    }
                }

                //Speichern der Einstellungen
                CurrentModel.SaveChanges();
                return true;
            }
            catch (Exception exception)
            {
                EFDebugging.Debugging.WriteLog("SaveHoliday Exception", exception);
            }

            return false;
        }

        /// <summary>
        /// Speichern/Hinzufügen des übergebenen Projekteintrags in der DB
        /// </summary>
        /// <param name="project">Der Projekteintrag der geändert/erstellt werden soll</param>
        /// <param name="userId">Die zugehörige UserId zum Projekt</param>
        /// <returns>TRUE->Speichern erfolgreich | FALSE->Fehler beim Speichern</returns>
        public bool SaveProject(EFWorktimeProject project, long userId)
        {
            try
            {
                //Wenn die Id=0, dann wurde der Eintrag noch nicht der DB hinzugefügt.
                if (project.Id == 0)
                {
                    //Suchen des User, damit wir den Eintrag seiner Projektliste hinzufügen können.
                    var user = (EFAuthentication)CurrentModel.EFBaseMenge.Find(userId);
                    if (user != null)
                    {
                        user.EFWorktimeSetting.EFWorktimeProject.Add(project);
                    }
                    else
                    {
                        return false;
                    }
                }

                //Speichern der Einstellungen
                CurrentModel.SaveChanges();
                return true;
            }
            catch (Exception exception)
            {
                EFDebugging.Debugging.WriteLog("SaveProject Exception", exception);
            }

            return false;
        }

        #endregion

        #region Konstruktor
        /// <summary>
        /// Initialize
        /// </summary>
        /// <param name="efModelContainer">Der Modelcontainer der für die Abfragen verwendet werden soll.</param>
        public WorktimeSettingsRepository(EFModelContainer efModelContainer)
        {
            CurrentModel = efModelContainer;
        }
        #endregion
    }
}
